package top.lishuoboy.jdbc.a5batch;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import lombok.extern.slf4j.Slf4j;
import top.lishuoboy.jdbc.a2conn.JDBCUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;

/**
 * 批量操作
 *
 * @author lishuoboy
 * @date 2021-12-19 23:07
 */
@Slf4j
public class A5BatchInsert {

    private static final int count = 1000000;

    public static void main(String[] args) throws Exception {
//        noBatchInnoDB();
        batchInnoDB();
    }

    /**
     * <h2>不使用批量。 ps 和 st 性能一样</h2>
     * rewriteBatchedStatements=true对此无效果
     * 100W条, InnoDB：1200秒, MyISAM：650秒;
     */
    public static void noBatchInnoDB() throws Exception {
        truncateTable();

        Connection conn = JDBCUtil.getConn();
        log.info("开始");
        TimeInterval timer = DateUtil.timer();
        timer.start();
        String sSql = "insert into class_innodb (classid,classname,remark) values ('class180','180班','sSql1')";
        PreparedStatement ps = conn.prepareStatement(sSql);
        for (int i = 1; i <= count; i++) {
            ps.executeUpdate();
            if (i % 10000 == 0) {
                ps.executeBatch(); // 对于不支持事务的引擎，不管是否自动提交，此行代码会数据落库
                log.debug("第" + i + "条");
            }
        }
        log.info("结束，用时{}", DateUtil.secondToTime((int) timer.intervalSecond()));
    }

    /**
     * <h2>批量插入，开启方法：</h2><br/>
     * 1、配置：url后面加参数 "?rewriteBatchedStatements=true"<br/>
     * 2、代码：ps.addBatch(sSql);  ps.executeBatch(); <br/>
     * 3、代码：conn.setAutoCommit(false);每10000条commit一次，最后conn.commit();(对mysql8性能没影响)<br/>
     * 100W条, InnoDB：22秒, MyISAM：25秒
     */
    public static void batchInnoDB() throws Exception {
        truncateTable();

        Connection conn = JDBCUtil.getConn();
//        conn.setAutoCommit(false);
        log.info("开始");
        TimeInterval timer = DateUtil.timer();
        timer.start();
        String sSql = "insert into class_innodb (classid,classname,remark) values ('class180','180班','sSql2')";
        PreparedStatement ps = conn.prepareStatement(sSql);
        for (int i = 1; i <= count; i++) {
            ps.addBatch(); //攒sql，开事务的情况下
            if (i % 10000 == 0) {
                ps.executeBatch(); // 对于不支持事务的引擎，不管是否自动提交，此行代码会数据落库
//                conn.commit();
                log.debug("第" + i + "条");
            }
        }
//        conn.commit();  // 1. 对mysql8性能没影响。 2.对于不支持事务的引擎，执行st.executeBatch()已提交，所以此行可以注释掉
        log.info("结束，用时{}", DateUtil.secondToTime((int) timer.intervalSecond()));
    }


    /**
     * 清表
     *
     * @author lishuoboy
     * @date 2021-12-19 23:43
     */
    public static void truncateTable() throws Exception {
        Connection conn = JDBCUtil.getConn();
        conn.createStatement().executeUpdate("TRUNCATE TABLE class_innodb");  // DDL 执行会立即提交事务
    }
}

